#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <pmc.h>

/*
#define COUNTER0 "p4-global-power-events"
#define COUNTER1 "p4-x87-fp-uop"
*/

#define COUNTER0 "p6-flops"
#define COUNTER1 "p6-cpu-clk-unhalted"

void do_something (void)
{
	float value;
	int i;

	for (i = value = 0; i < 100000; i++)
		value += (i >> 2) * 0.75;

	fprintf (stdout, "do_something value = %f\n", value);
}

int main (int argc, char *argv[])
{
	int i;
	pmc_id_t p[2];
	const struct pmc_cpuinfo *info;
	unsigned long long value[2],last[2];
	uint32_t cap[2];

	if (pmc_init() < 0)
	{
		fprintf (stderr, "Failed to run pmc_init()\n");
		perror ("perror: ");
		return 0;
	}
	if (pmc_cpuinfo (&info) != 0)
	{
		fprintf (stderr, "Failed to run pmc_cpuinfo()\n");
		perror ("perror: ");
		return 0;
	}

	if (pmc_allocate (COUNTER0, PMC_MODE_TC, 0, PMC_CPU_ANY, &p[0]) < 0)
	{
		fprintf (stderr, "Failed to pmc_allocate!\n");
		perror ("perror: ");
		return 0;
	}
	if (pmc_allocate (COUNTER1, PMC_MODE_TC, 0, PMC_CPU_ANY, &p[1]) < 0)
	{
		fprintf (stderr, "Failed to pmc_allocate!\n");
		perror ("perror: ");
		return 0;
	}

	if (pmc_start (p[0]) < 0 || pmc_start(p[1]) < 0)
	{
		fprintf (stderr, "Failed to pmc_start!\n");
		return 0;
	}
	if (pmc_capabilities (p[1], &cap[1]) < 0 || pmc_capabilities (p[0], &cap[0]) < 0 )
	{
		fprintf (stderr, "Failed to pmc_capabilities\n");
		perror ("perror: ");
		return 0;
	}
	fprintf (stderr, "CAPABILITIES: COUNTER[0]=%u (WR:%d) COUNTER[1]=%u (WR:%d)\n", cap[0], cap[0]&PMC_CAP_WRITE, cap[1], cap[1]&PMC_CAP_WRITE);

	last[0] = last[1] = 0;
	for (i = 0; i < 5; i++)
	{
		fprintf (stderr,"\n\n\nITERATION %d:\n", i);
		do_something();

		/* Read counters */
		if (pmc_read (p[0], &value[0]) < 0)
		{
			fprintf (stderr, "Failed to pmc_read\n");
			perror ("perror: ");
			return 0;
		}
		if (pmc_read (p[1], &value[1]) < 0)
		{
			fprintf (stderr, "Failed to pmc_read\n");
			perror ("perror: ");
			return 0;
		}
		fprintf (stdout, "PMC counters returned: %llu %llu\n", value[0], value[1]);

		/* Stop the counters */
		if (pmc_stop (p[0]) < 0 || pmc_stop (p[1]) < 0)
		{
			fprintf (stderr, "Failed to pmc_read\n");
			perror ("perror: ");
			return 0;
		}

		/* Write counters to 0 * reset * */
		if (pmc_write (p[0], 0) < 0)
		{
			fprintf (stderr, "Failed to pmc_read\n");
			perror ("perror: ");
			return 0;
		}
		if (pmc_write (p[1], 0) < 0)
		{
			fprintf (stderr, "Failed to pmc_read\n");
			perror ("perror: ");
			return 0;
		}

		/* Start counters */
		if (pmc_start (p[0]) < 0 || pmc_start (p[1]) < 0)
		{
			fprintf (stderr, "Failed to pmc_read\n");
			perror ("perror: ");
			return 0;
		}
	}

	return 0;
}
